#include "topcvt_api_c.h"

#include <string>
#include <map>
#include <exception>
using namespace std;

#include "topcvt_logutil.hpp"
#include "topcvt_component.hpp"

using namespace topcvt;

struct PktContext
{
	char* pBuffer;
	PktObject object;
};

static char errors[1024] = {0};

const char* getErrors()
{
	return errors;
}

void clearErrors()
{
	memset(errors,0x00,sizeof(errors));
}

PktContext_t* allocContext()
{
	try
	{
		PktContext_t* pctx = new PktContext();
		pctx->pBuffer = NULL;
		return pctx;
	}
	catch (const std::exception& e)
	{
		sprintf(errors, "allocContext error:%s",e.what());
		TLOG_ERROR("%s", errors);
		return NULL;
	}
}

void deallocContext(PktContext_t** pCtx)
{
	if (pCtx)
	{
		if (*pCtx)
		{
			if ((*pCtx)->pBuffer)
			{
				free((*pCtx)->pBuffer);
				(*pCtx)->pBuffer = NULL;
			}
			delete *pCtx;
			*pCtx = NULL;
		}
	}
}

void setPathLoadOption(mybool option)
{
	PktComponent::setPathLoadOption(option);
}

void setDefaultEncoding(const char* encoding)
{
	PktComponent::setDefaultEncoding(encoding);
}

void setString(PktContext_t* ctx, const char* key, const char* value)
{
	if (!ctx)
	{
		sprintf(errors, "nullpoint");
		TLOG_ERROR("%s", errors);
		return;
	}
	if (key)
	{
		ctx->object[key] = value;
	}
}

void setObject(PktContext_t* ctx, const char* key, PktContext_t* value)
{
	if (!ctx || !value)
	{
		sprintf(errors, "nullpoint");
		TLOG_ERROR("%s", errors);
		return;
	}
	ctx->object[key] = value->object;
}

void putArray(PktContext_t* ctx, PktContext_t* value)
{
	if (!ctx || !value)
	{
		sprintf(errors, "nullpoint");
		TLOG_ERROR("%s", errors);
		return;
	}
	ctx->object.append(value);
}

void getString(PktContext_t* ctx, const char* key, char* value)
{
	if (!ctx)
	{
		sprintf(errors, "nullpoint");
		TLOG_ERROR("%s", errors);
		return;
	}
	if (key)
	{
		string val = ctx->object.get(key);
		strcpy(value, val.c_str());
	}
}

void getObject(PktContext_t* ctx, const char* key, PktContext_t* value)
{
	if (!ctx || !value)
	{
		sprintf(errors, "nullpoint");
		TLOG_ERROR("%s", errors);
		return;
	}
	if (key)
	{
		try
		{
			value->object = ctx->object.get(key);
		}
		catch (const std::exception& e)
		{
			sprintf(errors, "getArray() error:%s", e.what());
		}
	}
}

void getArray(PktContext_t* ctx, int arrayIndex, PktContext_t* value)
{
	if (!ctx || !value)
	{
		sprintf(errors, "nullpoint");
		TLOG_ERROR("%s", errors);
		return;
	}
	if (!ctx->object.isValidIndex(arrayIndex))
	{
		sprintf(errors, "invalid index");
		TLOG_ERROR("%s", errors);
		return;
	}
	try
	{
		value->object = ctx->object[arrayIndex];
	}
	catch (const std::exception& e)
	{
		sprintf(errors, "getArray() error:%s", e.what());
	}
}

uint32_t getSize(PktContext_t* ctx)
{
	if (!ctx)
	{
		return 0;
	}
	return ctx->object.size();
}

void clear(PktContext_t* ctx)
{
	if (ctx)
	{
		(ctx->object).clear();
	}
}

const char* pack1(const char* pktPath, PktContext_t* ctx )
{
	if (!ctx)
	{
		sprintf(errors,"nullpoint");
		TLOG_ERROR("%s", errors);
		return NULL;
	}

	try {
		map<string, string> atx;
		string outdata = PktComponent::pack(pktPath, ctx->object, atx);
		if (ctx->pBuffer)
		{
			free(ctx->pBuffer);
		}
		ctx->pBuffer = strdup(outdata.c_str());
		if (!ctx->pBuffer)
		{
			sprintf(errors, "strdup() error:%s", strerror(errno));
			TLOG_ERROR("%s", errors);
			return NULL;
		}
		return ctx->pBuffer;
	}
	catch (const exception& e)
	{
		sprintf(errors, "pack() error:%s", e.what());
		return NULL;
	}
}

const char*  pack2(const char* pktPath, PktContext_t* ctx, const char* encoding)
{
	if (!ctx)
	{
		sprintf(errors, "nullpoint");
		TLOG_ERROR("%s", errors);
		return NULL;
	}
	try {
		map<string, string> atx;
		string outdata = PktComponent::pack(pktPath, ctx->object, encoding,atx);
		if (ctx->pBuffer)
		{
			free(ctx->pBuffer);
		}
		ctx->pBuffer = strdup(outdata.c_str());
		if (!ctx->pBuffer)
		{
			sprintf(errors, "strdup() error:%s", strerror(errno));
			TLOG_ERROR("%s", errors);
			return NULL;
		}
		return ctx->pBuffer;
	}
	catch (const exception& e)
	{
		sprintf(errors, "pack() error:%s", e.what());
		return NULL;
	}
}

int unpack1(const char* pktPath, const char* str, PktContext_t* ctx)
{
	if (!ctx || !str)
	{
		sprintf(errors, "nullpoint");
		TLOG_ERROR("%s", errors);
		return -1;
	}
	try
	{
		TLOG_TRACE("exec unpack()");
		map<string, string> atx;
		PktComponent::unpack(pktPath,str, ctx->object, atx);
	}
	catch (const std::exception& e)
	{
		sprintf(errors, "unpack() error:%s", e.what());
		TLOG_ERROR("%s", errors);
		return -1;
	}
	return 0;
}

int unpack2(const char* pktPath, const char* str, PktContext_t* ctx, const char* encoding)
{
	if (!ctx || !str)
	{
		sprintf(errors, "nullpoint");
		TLOG_ERROR("%s", errors);
		return -1;
	}
	try
	{
		map<string, string> atx;
		PktComponent::unpack(pktPath, str, ctx->object, encoding,atx);
	}
	catch (const std::exception& e)
	{
		sprintf(errors, "pack() error:%s", e.what());
		TLOG_ERROR("%s", errors);
		return -1;
	}
	return 0;
}